/**
 * 
 */
package de.bomzhi.mz.pflection.views;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.Viewer;

import com.powerflasher.fdt.core.outermodel.IClassModel;
import com.powerflasher.fdt.core.outermodel.IFunctionModel;
import com.powerflasher.fdt.core.outermodel.IInterfaceModel;
import com.powerflasher.fdt.core.outermodel.IMasterModel;
import com.powerflasher.fdt.core.outermodel.IOuterModelElement;

import de.bomzhi.mz.pflection.model.IndexOfModelSets;
import de.bomzhi.mz.pflection.model.PflectionValues;
import de.bomzhi.mz.pflection.model.PflectionValuesComputer;
import de.bomzhi.mz.pflection.model.SetOfModels;
import de.bomzhi.mz.pflection.model.SetOfStrongTypedModels;

class PflectionContentProvider implements IStructuredContentProvider {

	private static final String[] NO_METRICS = new String[] { "No metric values found." };

	public void inputChanged(final Viewer v, final Object oldInput,
			final Object newInput) {
	}

	public void dispose() {
	}

	public Object[] getElements(final Object parent) {
		PflectionValues values = null;
		if (parent instanceof SetOfModels) {
			PflectionValuesComputer metricValuesComputer = new PflectionValuesComputer();
			for (IOuterModelElement element : ((SetOfModels) parent)
					.getModels()) {
				element.accept(metricValuesComputer);
			}
			values = metricValuesComputer.getValues();
		}
		if (values != null) {
			List<Object> result = new ArrayList<Object>();
			Field[] fields = values.getClass().getFields();
			// TODO think about names register and equal name list
			// result.add(values.getNames());
			for (Field field : fields) {
				try {
					SetOfStrongTypedModels<? extends IOuterModelElement> valueOfField = (SetOfStrongTypedModels<? extends IOuterModelElement>) field
							.get(values);
					if (valueOfField.getSize() > 0) {
						result.add(valueOfField);
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			addParameters(values, result);
			addImplementations(values, result);
			addInheritansDepth(values, result);
			addMLOCs(values, result);
			addNumberOfConditions(values, result);
			addNumberOfBlocks(values, result);
			addNumberOfFlowTerminations(values, result);
			addNumberOfInternalReferences(values, result);
			addOutgoing(values, result);
			addIncoming(values, result);
			if (result.isEmpty()) {
				return NO_METRICS;
			}
			return result.toArray();
		}

		return NO_METRICS;
	}

	private void addParameters(PflectionValues values, List<Object> result) {
		List<SetOfStrongTypedModels<IFunctionModel>> parameters = values
				.getParameters();
		if (!parameters.isEmpty()) {
			result.add(new IndexOfModelSets<IFunctionModel>(parameters,
					"Parameters in functions"));
		}
	}

	private void addImplementations(PflectionValues values, List<Object> result) {
		List<SetOfStrongTypedModels<IInterfaceModel>> implementations = values
				.getImplemetntations();
		if (!implementations.isEmpty()) {
			result.add(new IndexOfModelSets<IInterfaceModel>(implementations,
					"Implementation Rate"));
		}
	}

	private void addInheritansDepth(PflectionValues values, List<Object> result) {
		List<SetOfStrongTypedModels<IClassModel>> inheritanceDepthValues = values
				.getInheritanceDepth();
		if (!inheritanceDepthValues.isEmpty()) {
			result.add(new IndexOfModelSets<IClassModel>(
					inheritanceDepthValues, "Inheritance Depth"));
		}
	}

	private void addMLOCs(PflectionValues values, List<Object> result) {
		List<SetOfStrongTypedModels<IFunctionModel>> mlocValues = values
				.getMLOCs();
		if (!mlocValues.isEmpty()) {
			result.add(new IndexOfModelSets<IFunctionModel>(mlocValues,
					"Method lines of code"));
		}
	}

	private void addNumberOfConditions(PflectionValues values,
			List<Object> result) {
		List<SetOfStrongTypedModels<IFunctionModel>> nocValues = values
				.getNumberOfConditions();
		if (!nocValues.isEmpty()) {
			result.add(new IndexOfModelSets<IFunctionModel>(nocValues,
					"Number of conditions in a function"));
		}
	}

	private void addNumberOfBlocks(PflectionValues values, List<Object> result) {
		List<SetOfStrongTypedModels<IFunctionModel>> nobValues = values
				.getNumberOfBlocks();
		if (!nobValues.isEmpty()) {
			result.add(new IndexOfModelSets<IFunctionModel>(nobValues,
					"Number of blocks in a function"));
		}
	}

	private void addNumberOfFlowTerminations(PflectionValues values,
			List<Object> result) {
		List<SetOfStrongTypedModels<IFunctionModel>> noftValues = values
				.getNumberOfFlowTerminations();
		if (!noftValues.isEmpty()) {
			result.add(new IndexOfModelSets<IFunctionModel>(noftValues,
					"Number of flow terminations in a function"));
		}
	}

	private void addNumberOfInternalReferences(PflectionValues values,
			List<Object> result) {
		List<SetOfStrongTypedModels<IFunctionModel>> noirValues = values
				.getNumberOfInternalReferences();
		if (!noirValues.isEmpty()) {
			result.add(new IndexOfModelSets<IFunctionModel>(noirValues,
					"Number of internal references in a function"));
		}
	}

	private void addOutgoing(PflectionValues values, List<Object> result) {
		List<SetOfStrongTypedModels<IMasterModel>> outgoing = values
				.getOutgoing();
		if (!outgoing.isEmpty()) {
			result.add(new IndexOfModelSets<IMasterModel>(outgoing,
					"Outgoing References"));
		}
	}

	private void addIncoming(PflectionValues values, List<Object> result) {
		List<SetOfStrongTypedModels<IMasterModel>> incoming = values
				.getIncoming();
		if (!incoming.isEmpty()) {
			result.add(new IndexOfModelSets<IMasterModel>(incoming,
					"Incoming References"));
		}
	}
}